package com.seng.resourcetycoon.gui.controllers;

import com.seng.resourcetycoon.core.enums.TowerState;
import com.seng.resourcetycoon.gui.models.ResourceTower;
import com.seng.resourcetycoon.gui.models.Upgrade;
import com.seng.resourcetycoon.gui.views.TowerStoreCellView;
import com.seng.resourcetycoon.manager.GameEnvironment;
import com.seng.resourcetycoon.util.SceneUtil;
import com.seng.resourcetycoon.util.ToastUtil;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;

import java.math.BigDecimal;
import java.net.URL;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.function.Consumer;

public class StoreController implements Initializable {

    @FXML
    private ListView<ResourceTower> towerListView;
    @FXML
    private ListView<Upgrade> upgradeListView;
    @FXML
    private Label currencyLabel;
    @FXML
    private Label itemPriceLabel;
    @FXML
    private Label upgradeLabel;


    @Override
    public void initialize(URL location, ResourceBundle resources) {
        towerListView.setCellFactory(listView1 -> new TowerStoreCellView());
        populateLists();

        addGenericChangeListener(towerListView.getItems(), GameEnvironment.getInstance()::removeTower, "Tower");
        addGenericChangeListener(upgradeListView.getItems(), GameEnvironment.getInstance()::removeUpgrade, "Upgrade");

        setupSelectionListeners();
        // 确保初始化时UI状态正确
        updateCurrencyLabel();
        updateUpgradeLabel();
    }

    private  <T> void addGenericChangeListener(ObservableList<T> items, Consumer<T> removeAction, String itemType) {
        ListChangeListener<T> listener = change -> {
            try {
                while (change.next()) {
                    if (!change.wasRemoved()) {
                            continue;
                    }
                    change.getRemoved().forEach(item -> {
                        try {
                            removeAction.accept(item);
                        } catch (Exception e) {
                            System.out.printf("Failed to remove " + itemType + ": " + e.getMessage()+"\n");
                        }
                    });
                    Platform.runLater(this::updateOnItemsChange);
                }
            } catch (Exception e) {
                System.out.printf("Error processing " + itemType + " change: " + e.getMessage()+"\n");
            }
        };
        items.addListener(listener);
    }

    private void populateLists() {
        ObservableList<ResourceTower> resourceTowers = FXCollections.observableArrayList();
        resourceTowers.addAll(GameEnvironment.getInstance().getTowers());
        towerListView.setItems(resourceTowers);

        ObservableList<Upgrade> upgrades = FXCollections.observableArrayList(
                GameEnvironment.getInstance().getUpgrades()
        );
        upgradeListView.setCellFactory(param -> new ListCell<Upgrade>() {
            @Override
            protected void updateItem(Upgrade item, boolean empty) {
                super.updateItem(item, empty);
                setText(empty || item == null ? null : item.getName());
            }
        });
        upgradeListView.setItems(upgrades);
    }


    private void setupSelectionListeners() {
        towerListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) ->
                Optional.ofNullable(newValue).ifPresent(tower -> {
                    itemPriceLabel.setText(tower.getSellPrice().toPlainString());
                }));

        upgradeListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) ->
                Optional.ofNullable(newValue).ifPresent(upgrade -> {
                }));
    }

    @FXML
    private void handleSellClick() {
        handleSelection(() -> {
            ToastUtil.showAlert("Must select one", "Error");
        }, (selected) -> {
            if (selected instanceof ResourceTower) {
                handleSell((ResourceTower) selected, GameEnvironment.getInstance()::removeTower);
                towerListView.getItems().remove(selected);
            } else if (selected instanceof Upgrade) {
                handleSell((Upgrade) selected, GameEnvironment.getInstance()::removeUpgrade);
                upgradeListView.getItems().remove(0);
            }
        });
    }

    @FXML
    private void handleClickOperation() {
        handleSelection(
                () -> ToastUtil.showAlert("Must select one Tower", "Error"),
                this::toggleTowerStateAndRefreshUI
        );
    }

    private void toggleTowerStateAndRefreshUI(Object o) {
        ResourceTower selected = validateAndCast(o);
        if (selected != null) {
            toggleTowerState(selected);
            towerListView.refresh();
        }
    }

    private void toggleTowerState(ResourceTower tower) {
        if (tower == null) return;

        TowerState nextState = tower.getState() == TowerState.IDLE ? TowerState.ACTIVE : TowerState.IDLE;
        tower.setState(nextState);
        try {
            GameEnvironment.getInstance().setTowerState(tower, nextState);
        } catch (Exception e) {
            // 异常处理逻辑
            e.printStackTrace();
        }
    }

    private ResourceTower validateAndCast(Object o) {
        if (o instanceof ResourceTower) {
            return (ResourceTower) o;
        } else {
            System.err.println("Object is not of type ResourceTower.");
            return null;
        }
    }

    @FXML
    private void HandleClickBack() {
        SceneUtil.getInstance().closeTmpStage();
    }

    private void handleSelection(Runnable onEmptySelection, Consumer<Object> onValidSelection) {
        ResourceTower selectedTower = towerListView.getSelectionModel().getSelectedItem();
        Upgrade selectedUpgrade = upgradeListView.getSelectionModel().getSelectedItem();
        if (selectedTower == null && selectedUpgrade == null) {
            onEmptySelection.run();
        } else {
            onValidSelection.accept(selectedTower != null ? selectedTower : selectedUpgrade);
        }
    }

    @FXML
    private void handleUpgradeClick() {
        if (GameEnvironment.getInstance().getUpgrades().isEmpty()) {
            showErrorAlert("No upgrades available", "Please purchase an upgrade first.");
            return;
        }

        ResourceTower selectedTower = towerListView.getSelectionModel().getSelectedItem();
        if (selectedTower == null) {
            showErrorAlert("No tower selected", "Please select a tower to upgrade.");
            return;
        }

        performUpgradeAndRefreshUI(selectedTower);
    }

    private void performUpgradeAndRefreshUI(ResourceTower tower) {
        try {
            tower.upgrade();
            if (!GameEnvironment.getInstance().getUpgrades().isEmpty()) {
                GameEnvironment.getInstance().getUpgrades().remove(0);
                upgradeListView.getItems().remove(0);
            }
            towerListView.refresh();
            updateUpgradeLabel();
        } catch (Exception e) {
            // 处理升级过程中可能出现的异常情况，如日志记录或提示用户
            showErrorAlert("Upgrade failed", "An error occurred during the upgrade process.");
        }
    }

    private void showErrorAlert(String header, String content) {
        ToastUtil.showAlert(header, content);
    }

    private <T> void handleSell(T item, java.util.function.Consumer<T> addToCollection) {
        BigDecimal price = (item instanceof ResourceTower) ? ((ResourceTower) item).getSellPrice() : ((Upgrade) item).getSellPrice();
        GameEnvironment.getInstance().addCoin(price);
        addToCollection.accept(item);
    }

    private void updateCurrencyLabel() {
        currencyLabel.setText("coins: " + GameEnvironment.getInstance().getCoin());
    }

    private void updateUpgradeLabel() {
        upgradeLabel.setText("upgrades: " + GameEnvironment.getInstance().getUpgrades().size());
    }

    private void updateOnItemsChange() {
        updateCurrencyLabel();
        updateUpgradeLabel();
    }
}